(function() {
    var proxyId = Tgm.id(), gInit = false, COMM = {
        START: 1,
        ING: 2,
        END: 0
    }, callback = Tgm.callback;
    var defaults = {
		//zIndex: zIndex,
        autoInit: true,
        autoDestory: false,
        // handler: '', // 拖拽的句柄
        // node: '', // 拖拽的节点
        proxy: true // 是否使用代理模式
        // fixX: false, // 限定X轴(只能左右拖动)
        // fixY: false, // 限定Y轴(只能上下拖动)
        // xMin: 0, // 最小X坐标
        // xMax: 0, // 最大X坐标 
        // yMin: 0, // 最小Y坐标
        // yMax: 0, // 最大Y坐标 
        // container: '', // 限定只能在该容器内拖拽
        // receive: '' // 接受的节点
    };
    var Drag = function(opts) {
        $.extend(this, defaults, opts);
        if (!this.handler) {
            this.handler = this.node;
        }
        var obj = $.extend({}, this);
        this.get = function(key) {
            return obj[key];
        };
        this.set = function(key, value) {
            return obj[key] = value;
        };
        if (this.autoInit) {
            this.init();
        }
    };
    Drag.prototype = (function() {
        var helper = {
            init: {
                action: function() {
                    helper.init.html.apply(this);
                    helper.init.node.apply(this);
                    helper.init.style.apply(this);
                    helper.init.event.apply(this);
                },
                html: function() {
                    if (!gInit) {
                        $(document.body).append('<div id="' + proxyId + '" class="mmc-el-drag-proxy"></div>');
                        gInit = true;
                    }
                },
                node: function() {
                    this.set('proxyNode', $('#' + proxyId));
                },
                style: function() {
                    this.get('handler').addClass('mmc-el-drag-handler');
                },
                event: function() {
                    var t = this, node = t.get('node'), p = t.get('proxyNode');
                    this.get('handler').bind('selectstart', function() {
                        return false;
                    });
                    p.bind('selectstart', function() {
                        return false;
                    });
                    this.get('handler').bind('mousedown', function(e) {
                        if (callback(t.get('bdr'), t.get('bdrp'), t.get('bdrs') || t) !== false) {
							t.set('zIndex', Tgm.get('zIndex'));
                            var o = t.get('node').offset(), z = t.get('zIndex');
                            $('body').bind('selectstart', function() {
                                return false;
                            });
                            t.set('sx', e.pageX - o.left);
                            t.set('sy', e.pageY - o.top);
                            if (t.get('proxy')) {
                                p.css({
                                    zIndex: z,
                                    position: 'absolute',
                                    top: o.top + 'px',
                                    left: o.left + 'px',
                                    width: node.outerWidth() + 'px',
                                    height: node.outerHeight() + 'px',
                                    display: 'block',
                                    border: '1px dashed #999'
                                });
                            } else {
                                var c = node.clone();
                                c.css({
                                    position: 'static',
                                    margin: 0
                                });
                                t.set('rpNode', c);
                                p.css({
                                    zIndex: z,
                                    position: 'absolute',
                                    top: o.top + 'px',
                                    left: o.left + 'px',
                                    display: 'block'
                                }).append(c);
                            }
                            node.css({
                                zIndex: z,
                                display: 'none'
                            });
                            t.set('isDraging', COMM.START);
                            t.render();
                        }
                    });
                }
            },
            render: {
                action: function() {
                    if (this.get('isDraging') == COMM.START) {
                        helper.render.event.apply(this);
                    }
                },
                event: function() {
                    var t = this, node = t.get('node'), handler = t.get('handler'), p = t.get('proxyNode'), sx = t.get('sx'), sy = t.get('sy'), receive = t.get('receive');
                    $(document).bind('mousemove', function(e) {
                        if (callback(t.get('odr'), t.get('odrp'), t.get('odrs') || t) !== false) {
                            t.set('isDraging', COMM.ING);
                            helper.rule.container.call(t);
                            helper.rule.x.call(t, e.pageX - sx);
                            helper.rule.y.call(t, e.pageY - sy);
                            p.css({
                                top: t.get('y') + 'px',
                                left: t.get('x') + 'px'
                            });
                            if(receive) {
                                if (helper.rule.receive.call(t, e.pageX, e.pageY)) {
                                    t.get('receive').addClass('mmc-el-drag-highlight');
                                } else {
                                    t.get('receive').removeClass('mmc-el-drag-highlight');
                                }
                            }
                        }
                    }).bind('mouseup', function(e) {
                        t.set('ex', e.pageX);
                        t.set('ey', e.pageY);
                        t.unrender();
                    });
                }
            },
            unrender: {
                action: function() {
                    var f = this.get('isDraging'), node = this.get('node'), p = this.get('proxyNode'), o = p.offset(), flag = false, rp;
                    if (f) {
                        node.show();
                        if (this.get('receive')) {
                            if (helper.rule.receive.call(this, this.get('ex'), this.get('ey'))) {
                                this.get('receive').removeClass('mmc-el-drag-highlight');
                                flag = true;
                            }
                        } else {
                            if (f == COMM.ING) {
                                flag = true;
                            }
                        }
                        if(flag) {
                            if (callback(this.get('bdrop'), this.get('bdropp'), this.get('bdrops') || this) !== false) {
                                node.css({
                                    top: o.top + 'px',
                                    left: o.left + 'px',
                                    position: 'absolute',
                                    margin: 0
                                });
								callback(this.get('adrop'), this.get('adropp'), this.get('adrops') || this);
                            }
                        }
                        this.set('ex', o.left);
                        this.set('ey', o.top);
                        rp = this.get('rpNode');
                        rp && rp.remove();
                        p.hide();
                        helper.unrender.event.apply(this);
                    }
                },
                event: function() {
                    $('body').unbind('selectstart');
                    $(document).unbind('mousemove').unbind('mouseup');
                    this.set('isDraging', COMM.END);
                }
            },
            destory: {
                action: function() {
                    this.get('handler').removeClass('mmc-el-drag-handler');
                    helper.destory.event.apply(this);
                },
                event: function() {
                    this.get('handler').unbind('selectstart').unbind('mousedown');
                    this.get('proxyNode').unbind('selectstart');
                }
            },
            ie6: {},
            rule: {
                x: function(x) {
                    var xMin, xMax;
                    if (this.get('fixX')) {
                        this.set('x', this.get('proxyNode').offset().left);
                    } else {
                        xMin = this.get('xMin'), xMax = this.get('xMax')
                        if (xMin && x < xMin) {
                            x = xMin;
                        }
                        if (xMax && x > xMax) {
                            x = xMax;
                        }
                        this.set('x', x);
                    }
                },
                y: function(y) {
                    var yMin, yMax;
                    if (this.get('fixY')) {
                        this.set('y', this.get('proxyNode').offset().top);
                    } else {
                        yMin = this.get('yMin'), yMax = this.get('yMax');
                        if (yMin && y < yMin) {
                            y = yMin;
                        }
                        if (yMax && y > yMax) {
                            y = yMax;
                        }
                        this.set('y', y);
                    }
                },
                container: function() {
                    var c = this.get('container'), o;
                    if (c) {
                        o = c.offset();
                        if (!this.get('xMin')) {
                            this.set('xMin', o.left);
                        }
                        if (!this.get('xMax')) {
                            this.set('xMax', o.left + c.outerWidth() - this.get('proxyNode').width());
                        }
                        if (!this.get('yMin')) {
                            this.set('yMin', o.top);
                        }
                        if (!this.get('yMax')) {
                            this.set('yMax', o.top + c.outerHeight() - this.get('proxyNode').height());
                        }
                    }
                },
                receive: function(x, y) {
                    var receive = this.get('receive'), ro = receive.offset();
                    return ((x > ro.left) && (x < ro.left + receive.outerWidth()) && (y > ro.top) && (y < ro.top + receive.outerHeight()));
                }
            }
        };
        return {
            constructor: Drag,
            init: function() {
                if (this.get('isInit')) {
                    return this;
                } else {
                    if (callback(this.get('bi'), this.get('bip'), this.get('bis') || this) !== false) {
                        helper.init.action.apply(this);
                        this.set('isInit', true);
                        callback(this.get('ai'), this.get('aip'), this.get('ais') || this);
                        return this;
                    }
                    return false;
                }
            },
            render: function() {
                if (!this.get('isInit')) {
                    this.init();
                }
                if (this.get('isRender')) {
                    return this;
                } else {
                    if (callback(this.get('br'), this.get('brp'), this.get('brs') || this) !== false) {
                        helper.render.action.apply(this);
                        this.set('isRender', true);
                        callback(this.get('ar'), this.get('arp'), this.get('ars') || this);
                    }
                }
            },
            unrender: function() {
                if (this.get('isRender')) {
                    if (callback(this.get('bu'), this.get('bup'), this.get('bus') || this) !== false) {
                        helper.unrender.action.apply(this);
                        this.set('isRender', false);
                        callback(this.get('au'), this.get('aup'), this.get('aus') || this);
                        if (this.get('autoDestory')) {
                            this.destory();
                        }
                        return this;
                    }
                } else {
                    return false;
                }
            },
            destory: function() {
                if (this.get('isInit')) {
                    if (callback(this.get('bd'), this.get('bdp'), this.get('bds') || this) !== false) {
                        helper.destory.action.apply(this);
                        this.set('isInit', false);
                        callback(this.get('ad'), this.get('adp'), this.get('ads') || this);
                        return this;
                    }
                } else {
                    return false;
                }
            },
            setHandler: function(handler) {
                if (this.get('isInit')) {
                    this.destory();
                    this.set('handler', handler);
                    this.init();
                }
            }
        };
    })();
	Tgm.reg('Drag', Drag);
})();
